﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using InIReaderExample.Properties;
using ini;

namespace InIReaderExample
{
	public partial class FrmExample : Form
	{
		private static readonly string path =
			Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
			             "iniReaderExample");

		private static readonly string settingsFile = Path.Combine(path, "Settings.ini");

		private readonly Dictionary<string, InIReader> reader = new Dictionary<string, InIReader>();
		private readonly Dictionary<InIReader, string> location = new Dictionary<InIReader, string>();

		public FrmExample()
		{
			InitializeComponent();
		}

		/// <summary>
		///     Loads the tree view.
		/// </summary>
		/// <param name="ini">The ini.</param>
		private void LoadTreeView(IEnumerable<KeyValuePair<string, InISection>> ini)
		{
			tvINI.Nodes.Clear();
			var node = tvINI.Nodes.Add(lbReader.SelectedItem.ToString());
			Example.ForeachThroughIni(node, ini);

			node.Expand();
		}

		/// <summary>
		///     Handles the Click event of the exitToolStripMenuItem control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void ExitToolStripMenuItemClick(object sender, EventArgs e)
		{
			Close();
		}

		private void ExportToolStripMenuItemClick(object sender, EventArgs e)
		{
			if (lbReader.SelectedIndex >= 0)
			{
				var tmp = reader[lbReader.SelectedItem.ToString()];
				SaveFileDialog dlg = new SaveFileDialog();
				if (location.ContainsKey(tmp))
					dlg.InitialDirectory = location[tmp];

				dlg.FileName = lbReader.SelectedItem.ToString();
				dlg.CheckFileExists = false;
				dlg.CheckPathExists = true;
				dlg.ValidateNames = true;
				dlg.AddExtension = false;
				dlg.DefaultExt = "ini";
				dlg.Filter =
					Resources
						.FrmExample_ImportInIFileToolStripMenuItemClick_INI_File____ini____ini_Text_File____txt__All_Files__________;

				if (dlg.ShowDialog() == DialogResult.OK)
				{
					Example.SaveIniToFile(dlg.FileName, tmp);
				}
			}
			else
			{
				lblInfo.Text = Resources.FrmExample_TbInIPrevTextChanged_No_Reader_Selected;
			}
		}

		/// <summary>
		///     BTNs the add click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void BtnAddClick(object sender, EventArgs e)
		{
			if (String.IsNullOrWhiteSpace(tbReaderName.Text))
			{
				tbReaderName.Focus();
				lblInfo.Text = Resources.frmExample_BtnAddClick_Please_enter_the_reader_s_name;
			}
			else if (!lbReader.Items.Contains(tbReaderName.Text))
			{
				reader.Add(tbReaderName.Text, Example.CreateEmptyReader());
				lbReader.SelectedIndex = lbReader.Items.Add(tbReaderName.Text);
				tbReaderName.Clear();
			}
			else
			{
				lblInfo.Text =
					Resources.FrmExample_ImportInIFileToolStripMenuItemClick_InI_Reader_with_the_same_name_does_already_exist;
			}
		}

		/// <summary>
		///     BTNs the remove click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void BtnRemoveClick(object sender, EventArgs e)
		{
			if (lbReader.SelectedIndex < 0)
			{
				lbReader.Focus();
				lblInfo.Text = Resources.FrmExample_BtnRemoveClick_Select_first_a_Reader__then_press_delete;
			}
			else
			{
				MnuLbReaderExcludeClick(sender, e);
			}
		}

		/// <summary>
		///     Lbs the reader selected index changed.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void LbReaderSelectedIndexChanged(object sender, EventArgs e)
		{
			Update();
		}

		private new void Update()
		{
			if (lbReader.SelectedIndex >= 0)
			{
				var ini = reader[lbReader.SelectedItem.ToString()];

				tbInIPrev.Lines = Example.ConvertIniReaderToString(ini).Split('\n');
				LoadTreeView(ini);
			}
			else
			{
				tbInIPrev.Text = "";
				tvINI.Nodes.Clear();
			}	
		}

		/// <summary>
		///     Imports the in I file tool strip menu item click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void ImportInIFileToolStripMenuItemClick(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.CheckFileExists = true;
			dlg.CheckPathExists = true;
			dlg.ValidateNames = true;
			dlg.AddExtension = false;
			dlg.DefaultExt = "ini";
			dlg.Filter =
				Resources
					.FrmExample_ImportInIFileToolStripMenuItemClick_INI_File____ini____ini_Text_File____txt__All_Files__________;

			if (dlg.ShowDialog() == DialogResult.OK)
			{
				try
				{
					string name = Path.GetFileNameWithoutExtension(dlg.FileName);
					if (name != null && !lbReader.Items.Contains(name))
					{
						InIReader tmp = Example.LoadIniFromFile(dlg.FileName);

						reader.Add(name, tmp);
						location.Add(tmp, name);

						lbReader.SelectedIndex = lbReader.Items.Add(name);

						lblInfo.Text = Resources.FrmExample_ImportInIFileToolStripMenuItemClick_Loading_succesfull;
					}
					else
					{
						// TODO: Rename
						lblInfo.Text =
							Resources.FrmExample_ImportInIFileToolStripMenuItemClick_InI_Reader_with_the_same_name_does_already_exist;
					}
				}
				catch (Exception ex)
				{
					lblInfo.Text = ex.Message;
				}
			}
		}

		private void TbInIPrevTextChanged(object sender, EventArgs e)
		{
			if (lbReader.SelectedIndex >= 0)
			{
				try
				{
					InIReader newReader = Example.CreateReaderFromString(tbInIPrev.Text); //String.Join("\n", tbReaderName.Lines));
					reader[lbReader.SelectedItem.ToString()] = newReader;

					LoadTreeView(newReader);

					lblInfo.Text = Resources.FrmExample_TbInIPrevTextChanged_IniFile_updated;
				}
				catch (Exception ex)
				{
					lblInfo.Text = ex.Message;
				}
			}
			else
			{
				lblInfo.Text = Resources.FrmExample_TbInIPrevTextChanged_No_Reader_Selected;
			}
		}

		/// <summary>
		///     FRMs the example form closing.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="FormClosingEventArgs" /> instance containing the event data.
		/// </param>
		private void FrmExampleFormClosing(object sender, FormClosingEventArgs e)
		{
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			else
			{
				DirectoryInfo dir = new DirectoryInfo(path);
				foreach (var fileInfo in dir.GetFiles()) fileInfo.Delete();
				foreach (var directoryInfo in dir.GetDirectories()) directoryInfo.Delete(true);
			}

			InIReader settings = new InIReader();

			foreach (var ini in reader)
			{
				if (location.ContainsKey(ini.Value))
				{
					settings.Add("Last Files", ini.Key, location[ini.Value]);
				}
				else
				{
					Random random = new Random((int)DateTime.Now.Ticks);
					string file;
					do
					{
						file = String.Concat("tmp", random.Next(0, 99999),".ini");	
					} while (File.Exists(Path.Combine(path, file)));

					file = Path.Combine(path, file);
					ini.Value.Save(file);
					settings.Add("Last Files", ini.Key, file);
				}
			}

			settings.Add("General", "Index", lbReader.SelectedIndex.ToString(CultureInfo.InvariantCulture));

			settings.Save(settingsFile);
		}

		/// <summary>
		///     FRMs the example load.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">
		///     The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void FrmExampleLoad(object sender, EventArgs e)
		{
			if (!Directory.Exists(path))
				Directory.CreateDirectory(path);

			if (File.Exists(settingsFile))
			{
				InIReader settings = new InIReader(settingsFile);
				if (settings.ContainsKey("Last Files"))
				{
					foreach (var pair in settings["Last Files"])
					{
						if (File.Exists(pair.Value))
						{
							var tmp = new InIReader(pair.Value);
							reader.Add(pair.Key, tmp);
							lbReader.SelectedIndex = lbReader.Items.Add(pair.Key);

							if (!path.Equals(Path.GetDirectoryName(pair.Value)))
								location.Add(tmp, pair.Value);
						}
						else
						{
							lblInfo.Text =
								Resources
									.FrmExample_FrmExampleLoad_One_or_multiple_files_could_not_be_loaded__because_they_do_not_exist_anymore_;
						}
					}
				}

				if (settings.ContainsKey("General"))
				{
					var general = settings["General"];
					// TODO: Change with typesafe interface
					if (general.ContainsKey("index"))
					{
						int i;
						if (int.TryParse(general["index"], out i))
							if(lbReader.Items.Count > i)
								lbReader.SelectedIndex = i;
					}
				}
			}
		}

		/// <summary>
		/// Lbs the reader mouse down.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="MouseEventArgs" /> instance containing the event data.</param>
		private void LbReaderMouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right)
			{
				lbReader.SelectedIndex = lbReader.IndexFromPoint(e.Location);
				if (lbReader.SelectedIndex == -1)
				{
					mnuLbReader.Hide();
				}
			}
		}

		/// <summary>
		/// Mnus the lb reader opening.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="CancelEventArgs" /> instance containing the event data.</param>
		private void MnuLbReaderOpening(object sender, CancelEventArgs e)
		{
			if (lbReader.SelectedIndex > -1)
			{
				foreach (object item in mnuLbReader.Items)
				{
					var tmp = item as ToolStripMenuItem;
					if(tmp != null)
						tmp.Enabled = true;
				}

				InIReader ini = reader[lbReader.SelectedItem.ToString()];
				if (!location.ContainsKey(ini))
					mnuLbReaderExclude.Enabled = false;
			}
			else
			{
				foreach (object item in mnuLbReader.Items)
				{
					var tmp = item as ToolStripMenuItem;
					if(tmp != null)
						tmp.Enabled = false;
				}
			}
		}

		/// <summary>
		/// Mnus the lb reader save click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MnuLbReaderSaveClick(object sender, EventArgs e)
		{
			ExportToolStripMenuItemClick(sender, e);
		}

		/// <summary>
		/// Handles the Click event of the mnuLbReaderExclude control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MnuLbReaderExcludeClick(object sender, EventArgs e)
		{
			if (lbReader.SelectedIndex > -1)
			{
				var tmp = reader[lbReader.SelectedItem.ToString()];
				location.Remove(tmp);
				reader.Remove(lbReader.SelectedItem.ToString());

				lbReader.Items.RemoveAt(lbReader.SelectedIndex);
				if (lbReader.Items.Count > 0)
					lbReader.SelectedIndex = lbReader.Items.Count - 1;
			}
		}

		/// <summary>
		/// Mnus the lb reader delete click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MnuLbReaderDeleteClick(object sender, EventArgs e)
		{

			if (lbReader.SelectedIndex > -1)
			{
				var tmp = reader[lbReader.SelectedItem.ToString()];
				if(location.ContainsKey(tmp) && File.Exists(location[tmp]))
					File.Delete(location[tmp]);

				MnuLbReaderExcludeClick(sender, e);
			}
		}

		/// <summary>
		/// Mnus the lb reader rename click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MnuLbReaderRenameClick(object sender, EventArgs e)
		{
			if (lbReader.SelectedIndex > -1)
			{
				string name = lbReader.SelectedItem.ToString();
				FrmRename wnd = new FrmRename(name, reader.Keys);
				if (wnd.ShowDialog() == DialogResult.OK)
				{
					reader.Add(wnd.FileName, reader[name]);
					reader.Remove(name);

					lbReader.Items[lbReader.SelectedIndex] = wnd.FileName;
				}
			}
		}

		/// <summary>
		/// Shows the tree view tool strip menu item click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void ShowTreeViewToolStripMenuItemClick(object sender, EventArgs e)
		{
			scEditors.Panel1.Visible = showTreeViewToolStripMenuItem.Checked;
			scEditors.Panel1Collapsed = !showTreeViewToolStripMenuItem.Checked;
			showTextEditorToolStripMenuItem.Enabled = showTreeViewToolStripMenuItem.Checked;
		}

		/// <summary>
		/// Shows the text editor tool strip menu item click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void ShowTextEditorToolStripMenuItemClick(object sender, EventArgs e)
		{
			scEditors.Panel2.Visible = showTextEditorToolStripMenuItem.Checked;
			scEditors.Panel2Collapsed = !showTextEditorToolStripMenuItem.Checked;
			showTreeViewToolStripMenuItem.Enabled = showTextEditorToolStripMenuItem.Checked;
		}

		/// <summary>
		/// Merges the files tool strip menu item click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MergeFilesToolStripMenuItemClick(object sender, EventArgs e)
		{
			FrmMergeFiles wnd = new FrmMergeFiles(reader.Keys.ToList());
			if (wnd.ShowDialog() == DialogResult.OK)
			{
				Example.MergeIniReader(reader[wnd.File1], reader[wnd.File2], wnd.Replace);
			}
		}

		/// <summary>
		/// Handles the Click event of the mergeSectionsToolStripMenuItem control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
		private void MergeSectionsToolStripMenuItemClick(object sender, EventArgs e)
		{
			FrmCopySections wnd = new FrmCopySections(reader);
			wnd.ShowDialog();

			Update();
		}
	}
}